/*
 * Author: vdaras
 */

#include "State.h"

#include "EngineCore.h"
#include "EntityManager.h"
#include "Globals.h"
#include "LevelMap.h"
#include "audio/AudioManager.h"
#include "ServiceLocator.h"
#include "parsers/LevelParser.h"

State::State(EngineCore *engine)
:
m_guiContents(NULL),
m_tileProperties(NULL),
m_levelMap(NULL),
m_entityManager(NULL),
m_physicsManager(NULL),
m_renderingManager(NULL)
{
    Globals *global = Globals::GetInstance( );

    int screenWidth = global->GetScreenWidth( );
    int screenHeight = global->GetScreenHeight( );

    m_guiContents = new gui::Container( "MainContainer", 0, 0, screenWidth, screenHeight );
    m_physicsManager = new PhysicsManager;
    m_renderingManager = new RenderingManager;
    m_renderingManager->Init( engine->GetGraphicsCore( )->GetSdlScreen( ), engine->GetCamera( ) );
    m_entityManager = new EntityManager;
    m_audioManager = new al::AudioManager;
}

State::~State()
{
    //delete m_guiContents; the gui screen deletes this
    delete m_tileProperties;
    delete m_levelMap;

    //must be called first because Entity logics
    //have pointers to the physics and rendering managers
    delete m_entityManager;

    delete m_physicsManager;
    delete m_renderingManager;
    delete m_audioManager;
}

/**
 * Renders this State.
 *
 * @param gCore - handle to the engine's graphics core.
 */

void State::Render(sdl::GraphicsCore *gCore)
{
    m_renderingManager->RenderLayers( gCore );
}

/**
 * Updates the State by updating the Entity, Physics and Audio managers.
 *
 * @param deltaTime - time passed since last call.
 */

void State::Update(unsigned deltaTime)
{
    m_entityManager->UpdateEntities( );

    m_physicsManager->Update( deltaTime );

    m_entityManager->BurryEntities( );

    m_audioManager->Update( );
}

/**
 * Pushes keyboard events to the Entities. Override to extend functionality.
 *
 * @param event: an keyboard event occurred.
 */

void State::OnKeyboardEvent(KeyboardEvent &event)
{
    if( !event.IsConsumed( ) )
    {
        m_entityManager->PushKeyboardInput( event );
    }
}

/**
 * @return A pointer to the State's rendering manager.
 */

RenderingManager *State::GetRenderingManager()
{
    return m_renderingManager;
}

/**
 * @return A pointer to the State's entity manager.
 */

EntityManager *State::GetEntityManager()
{
    return m_entityManager;
}

/**
 * @return A pointer to the State's physics manager.
 */

PhysicsManager *State::GetPhysicsManager()
{
    return m_physicsManager;
}

/**
 * 
 * @return A pointer to the State's Audio Manager. 
 */
AudioManager *State::GetAudioManager()
{
    return m_audioManager;
}

/**
 * Loads a tile map.
 *
 * @param mapName - name of the map to load.
 * @param layerName - layer to register the map on.
 * @return a boolean value indicating if loading was successful or not.
 */

bool State::LoadMap(const std::string& mapName, const std::string& layerName)
{
    if( !m_levelMap )
    {
        m_levelMap = new LevelMap;
        //parse map
        FileParser::LevelParser parser( mapName.c_str( ) );
        m_tileProperties = new TileProperties;
        m_tileProperties->ParsePoperties( "tileProperties.xml" );
        parser.ParseLevel( m_levelMap, m_tileProperties );
        //add map into physics manager
        m_physicsManager->SetTileProperties( m_tileProperties );
        m_physicsManager->SetCurrentMap( m_levelMap );

        //register map to the renderer
        //m_renderingManager->RegisterDrawable( m_levelMap->GetBackground(), layerName );
        m_renderingManager->RegisterDrawable( m_levelMap, layerName.c_str( ) );
        //set camera boarders based on map
        ServiceLocator<Camera>::GetService( )->SetBorders( m_levelMap->GetWidth( ) * m_levelMap->GetTileWidth( ), m_levelMap->GetHeight( ) * m_levelMap->GetTileHeight( ) );

        return true;
    }

    return false;
}

void State::UnLoadMap()
{
    if( m_levelMap )
    {
        m_physicsManager->SetCurrentMap( NULL );
        m_renderingManager->UnregisterDrawable( m_levelMap );
        ServiceLocator<Camera>::GetService( )->SetBorders( 0, 0 );
        m_levelMap = NULL;
        this->m_entityManager->DestroyAllEntities();
        this->m_physicsManager->ClearParticleSystems();
    }
}

/**
 * Returns a pointer to the gui contents of this State.
 *
 * @return a gui::Container that belongs to this State.
 */

gui::Container* State::GuiContents()
{
    return m_guiContents;
}